{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# anything about human body detect\n",
    "<!--TOC-->\n",
    "- [头部姿态估计](#头部姿态估计)\n",
    "  - [相机标定方法](#相机标定方法)\n",
    "  - [传统机器学习方法](#传统机器学习方法)\n",
    "  - [深度学习网络](#深度学习网络)\n",
    "      - [Hopenet](#Hopenet)\n",
    "      - [HyperFace](#HyperFace)\n",
    "<!--/TOC-->\n",
    "\n",
    "## 头部姿态估计 (Head Pose Estimation) \n",
    "<font style=\"color:red\" size=4> 比较经典的Head Pose Estimation 算法的步骤一般为：\n",
    "    - 2D人脸关键点检测\n",
    "    - 3D人脸模型匹配\n",
    "    - 求解3D点和对应2D点的转换关系\n",
    "    - 根据旋转矩阵求解欧拉角\n",
    "</font>\n",
    "\n",
    "<font style=\"color:blue\" size=3>\n",
    " 原理：众所周知一个物体相对于相机的姿态可以使用旋转矩阵和平移矩阵来表示。  \n",
    "    平移矩阵：物体相对于相机的空间位置关系矩阵，用T表示；  \n",
    "    旋转矩阵：物体相对于相机的空间姿态关系矩阵，用R表示；  \n",
    "    3D和2D的对应关系如图：  \n",
    "    <img src=\"3Dconnect2D.png\", width=320, heigth=240>\n",
    "</font>\n",
    "\n",
    "## 应用场景和目的\n",
    "1. 注意力检测：通过判断头部姿态可以判断人的注意力情况，司机，学生\n",
    "2. 行为分析：通过视频监控分析来分析人的动向、等等\n",
    "3. 人际互动：头部动作有时可以表示意义，传递信息。(摇头否认，点头同意等等)\n",
    "4. 实现追踪：也可称为眼球跟踪。实现追踪可以用在游戏领域，\n",
    "\n",
    "### 相机标定方法\n",
    "**要先了解相机标定:** 在图像测量过程以及机器视觉应用中，为确定空间物体表面某点的三维几何位置与其在图像中对应点之间的相互关系，必须建立相机成像的几何模型，这些几何模型参数就是相机参数。在大多数条件下这些参数必须通过实验与计算才能得到，这个求解参数的过程就称之为相机标定（或摄像机标定）。无论是在图像测量或者机器视觉应用中，相机参数的标定都是非常关键的环节，其标定结果的精度及算法的稳定性直接影响相机工作产生结果的准确性。因此，做好相机标定是做好后续工作的前提，提高标定精度是科研工作的重点所在。\n",
    "**相机标定相关问题**\n",
    "1. 坐标系的转换\n",
    "  - 世界坐标系\n",
    "  - 相机坐标系\n",
    "  - 世界坐标系转换为相机坐标系\n",
    "  - 像素坐标系、图像坐标系\n",
    "  - 针孔成像原理\n",
    "  - 世界坐标系转换为像素坐标系\n",
    "2. 相机内参与畸变参数\n",
    "  - 相机内参\n",
    "  - 畸变参数：径向畸变、切向畸变\n",
    "  - opencv中的畸变模型\n",
    "  - 张氏标定中的畸变模型\n",
    "  - Tasi畸变模型\n",
    "3. 相机标定\n",
    "\n",
    "### 传统机器学习方法\n",
    "1. 数据预处理：\n",
    "landmarks里面包含了mat文件，这些mat文件保存了AFW、HELEN、IBUG和LFPW内图片的关键点信息。用matlab打开任一mat文件，你将看到两个数据信息：pts_2d和pts_3d。pts_2d应该是人脸跟踪算法比较容易获得的人脸关键点位置信息，这也是本文用到的数据；pts_3d是真实脸部关键点位置信息，但不知道这个数据能不能用算法得到，如果可以，这种数据应该更适合去做训练。回过头看那几个包含图片的数据集，里面分别是图片和对应的mat文件，mat文件信息有Color_Para、Exp_Para、Illum_Para、Pose_Para、pt2d、roi、Shape_Para和Tex_Para。这里面虽然也有pt2d数据，但不可用，为什么？小伙伴们可以自己去看看，就当作业。剩下的再说说Pose_Para吧，这个是没有问题的，每个Pose_Para有7个数据，分别表示pitch、yaw、roll、tdx、tdy、tdz、scale_factor，CV_life君觉得上面的tdx、tdy和tdz应该是平移矩阵的数据，scale_factor表示相机变换的尺度系数，\n",
    "2. 特征提取：\n",
    "  数据预处理的下一步是特征提取和归一化。CV_life君使用landmarks数据作为特征提取的原始数据，当然小伙伴也可以尝试其他特征，比如SIFT特征或者pts_3d数据等。将原始数据直接作为特征来使用，CV_life君觉得这样不妥，因为原始数据和pose数据相关性可能没那么强，会影响预测精度，所以决定采用相对位置的策略：即将第28关键点位置为基准，以第28关键点和31关键点之间的距离为归一化标准，对数据进行处理。为什么选择这两个点？首先在多数场景下，这两个点都可以很好地被侦测到；其次，这两个点位置比较稳定，无论什么样的人脸，这两个关键点都会存在。\n",
    "3. SVM(SVR)训练和预测：\n",
    "这里CV_life君用到的是SVM中的SVR算法，因为Head Pose Estimation属于回归问题。\n",
    "4. C++文件读取和写入：\n",
    "5. OpenCV和dlib的使用：\n",
    "6. 其他的小收获\n",
    "\n",
    "### 深度学习网络\n",
    "1. Hopenet\n",
    "本文提出了一种简洁和鲁棒的方式来确定姿态，通过训练一个multi-loss的卷积神经网络。直接使用RGB结合分类和回归损失来预测Euler angles（yaw，pitch and roll）。  \n",
    "<img src=\"hopenet.png\">\n",
    "<font style=\"color:red\" size=4>\n",
    "    本文提出使用3个分离的losses，为每一个角度。每个loss由两部分组成：a binned pose classification and a regression component 组成。  \n",
    "    \n",
    "    实现细节:   \n",
    "    \n",
    "    1. 对欧拉角（Yaw，Pitch，Roll）按角度区间进行分类，比如3度，那么Yaw：-90-+90，可以分成180/3= 60个类别，Pitch和Roll同Yaw角类似。这样就可以进行分类任务了。   \n",
    "    \n",
    "    2. 对分类的结果恢复成实际的角度，类别*3-90，在和实际的角度计算回归损失。    \n",
    "    \n",
    "    3. 最后将回归损失和分类损失进行合并来得到最后的损失，回归损失的前面增加了一个权重系数  \n",
    "</font>\n",
    "开源代码：https://github.com/natanielruiz/deep-head-pose  \n",
    "\n",
    "2. HyperFace\n",
    " 核心导读：\n",
    "MultiTask，将人脸检测、关键点定位、头部角度估计和性别识别综合起来。很慢，TITAN-X 要3S每图.合起来的效果图  \n",
    "<img src=\"hyperface_xiaoguo.jpg\">\n",
    "\n",
    "**Introduction**  \n",
    "\n",
    "(1) 有研究表明，我们需要的特征分布在网络每一层：前面的层对边缘和角点响应较大，比较适合关键点定位和姿态估计；后面的层则较适合人脸检测和性别识别。  \n",
    "(2) 实验证明，MultiTask比独立的学习要好；融合中间层特征效果也有提升。  \n",
    "\n",
    "(3) 本文提供了两种后处理方法：iterative region proposals 和 landmarks-based non-maximum suppression，可以进一步提升性能  \n",
    "\n",
    "(4) 本文将R-CNN 和 (R-CNN + MultiTask + 中间层特征融合)进行了对比；  \n",
    "\n",
    "\n",
    "<font style=\"color：red\" size=4> 先用Selective Search方法选出一些候选框，然后reszie到227×227,最后送入下面的网络。如果窗口被分类为人脸，则再去算关键点、姿态和性别。 </font>\n",
    "<img src=\"hyperface.jpg\">\n",
    "\n",
    "<font color=\"blue\"> <strong>Training</strong> </font>\n",
    "\n",
    "<p>训练使用AFLW数据集，该数据集包含人脸框、21个关键点、性别和<font color=\"red\"> <strong>机器算出来的姿态角度</strong> </font>（我很震惊作者竟然用这个角度）。</p>\n",
    "\n",
    "<p><font color=\"red\"> <strong>Face Detection:</strong></font></p>\n",
    "<p>使用Selective Search方法选择候选框，IOU大于0.5视为正样本，小于0.35视作负样本，其余的忽略掉。</p>\n",
    "\n",
    "<p><font color=\"red\"> <strong>Landmark Localization:</strong></font></p>\n",
    "\n",
    "<p>针对IOU大于0.35的窗口。</p>\n",
    "\n",
    "<p>使用AFLW进行21点回归，ground truth是按照下式计算的归一化偏移量:</p>\n",
    "\n",
    "<p>\\((a_i,b_i)=(\\frac{x_i-x}{w},\\frac{y_i-y}{h})\\)</p>\n",
    "\n",
    "<p><font color=\"red\"> <strong>Learning Visibility:</strong></font></p>\n",
    "对于IOU大于0.35的窗口，都会给出这样一个“可见因子”，来表示对应关键点是否可见。\n",
    "这里于是采用最简单的Euclidean Loss:  \n",
    "\n",
    "<p><font color=\"red\"> <strong>Pose Estimation:</strong></font></p>\n",
    "IOU大于0.5的才会估计姿态：roll (p1), pitch (p2) and yaw (p3)。\n",
    "<p><font color=\"red\"> <strong>Gender Recognition:</strong></font></p>\n",
    "对于IOU大于0.5的区域，计算一个二分类Loss。最终的loss是加权计算的：\n",
    "\n",
    "相关loss函数的计算：\n",
    "<img src=\"loss1.png\">  \n",
    "<img src=\"loss2.png\">"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
